#ifndef SEARCHALGO_H_INCLUDED
#define SEARCHALGO_H_INCLUDED


#include "go.h"
#include <deque>
#include <vector>

#define DEPTH 2 /** 对于minmax搜索(非禁着点皆为节点)深度为2已经是极限 **/

using namespace std;

class ABMinMax;
class Judgment;
class Nodes;
class NodesOperator;
class Go;

typedef int hash_key_t; //type of int to store the hashvalue
typedef deque<Nodes*> sub_nodes_t; //a list to hold ptr of nodes of the parent node

class ABMinMax
{
public:
    ABMinMax(Go * mirrorCore); //constructor
    ~ABMinMax(); //destructor

public:
    //极小极大搜索,alpha-beta剪枝
    coordinate alphaBetaMinMaxSearch();

private:
    float alpha_beta_max(const Nodes * const cur_Node, const int cur_depth, const float alpha, const float beta);
    float alpha_beta_min(const Nodes * const cur_Node, const int cur_depth, const float alpha, const float beta);
    void expand_subNodes(const Nodes * const cur_Node, sub_nodes_t *ptr_subNodes);
    float get_score(const pair<int,int> temp_pair);
    /*void find_subNode(const int parent_node[][DIMENSION], int sub_node[][DIMENSION], sub_nodes_t *ptr_subNodes,
                              const int x, const int y, const int cur_depth);*/
    inline Nodes * create_Node(const int board[][DIMENSION], const Nodes * const parent_Node);
    coordinate find_diff_parent(const Nodes * const cur_Node); //return move between parent&current
    //void modify_Path(int cur_depth, const Nodes * const cur_Node);

private:
    Judgment *myJudgment;
    NodesOperator *nodesOperator; /** important to clr memories in deque before finish certain func **/
    Go *mirrorCore;

    //const Nodes * _path[DEPTH+1]; //record the path of the result
    const Nodes * next_Move_Node; //its the biggest-value Node in the DEPTH of 1, also the result
    int whos_turn; //it represents the beginning status of the whos_turn of the passed-in core
};

/** capsuliert 2D-Board Array **/
class Nodes
{
public:
    Nodes(const int board[][DIMENSION], const Nodes * parent_Node);
    ~Nodes();
    Nodes & operator = (const Nodes & rightNode);
    //int & operator [] (int index);

    void getBoard(int out_board[][DIMENSION]) const;
    const Nodes * getParent() const; //possible to return void pointer, addtional check is necessary

private:
    int _board[DIMENSION][DIMENSION];
    const Nodes * parent_Node;

};

/** nodesOperator **/
class NodesOperator
{
public:
    NodesOperator();
    ~NodesOperator();

    void addNode_back(Nodes * node);

private:
    vector<Nodes*> nodesOperator;
};

class ZobristHashTools
{
public:
    ZobristHashTools();
    ~ZobristHashTools();

public:
    hash_key_t createHashKey(const int board[][DIMENSION]); //you must run this function once before do anyting else
                                                          //to create a key and table
    hash_key_t modifyOnePosition(hash_key_t hashKey, int pos_x, int pos_y, int color);

private:
    void resetHashTable();
    void createHashTable();

private:
public://test
    int hashTable[DIMENSION][DIMENSION][3]; //[0]->BLACK [1]->WHITE [2]->GRID
};

/** inline funcs **/
inline Nodes * ABMinMax::create_Node(const int board[][DIMENSION], const Nodes * const parent_Node)
{
    Nodes * temp_Node = new Nodes(board, parent_Node);

    nodesOperator->addNode_back(temp_Node);

    return temp_Node;
}
#endif // SEARCHALGO_H_INCLUDED
